import  Flox from "./Flox";
var d3 = require("d3");

var FlowImporter = ( function (d3) {
    "use strict";
    var my = {};


    //倒入州的中心点
    function importStateNodes(callback) {
        var stateNodePath = "FlowData.json",
            stateNodes = [],
            newStNode,
            stateNodeData,
            row, i;

        d3.json(stateNodePath, function (flows) {
            var d = flows.nodes;
            for (i = 0; i < d.length; i += 1) {
                row = d[i];
                if (row.id / 100 >= 2) {//取消2级的id
                    continue;
                }
                newStNode = new Flox.Point(Number(row.y), Number(row.x), 1, row.id);
                // Verifying that the node can be projected before adding

                newStNode.FIPS = row.id;
                newStNode.STATEFP = row.id;//注意是id 不是sid

                newStNode.name = row.name;
                newStNode.totalIncomingFlow = 0;
                newStNode.totalOutgoingFlow = 0;
                newStNode.netFlow = 0;
                newStNode.type = "state";
                stateNodes.push(newStNode);

            }
            callback(stateNodes);
        })
    }

    function findStateNode(nodes, stateFIPS) {
        var i, j;

        for (i = 0, j = nodes.length; i < j; i += 1) {
            if (Number(nodes[i].STATEFP) === Number(stateFIPS)) {
                return nodes[i];
            }
        }
    }

    function findNodeByID(nodes, id) {
        var i, j, nodeID;

        // Can id be converted into a number? If so, do it.
        if (!isNaN(Number(id))) {
            id = Number(id);
        }

        // Loop through the nodes.
        // If node.id matches id, return the node!
        for (i = 0, j = nodes.length; i < j; i += 1) {
            nodeID = nodes[i].id;

            // try converting the nodeID to a number.
            if (!isNaN(Number(nodeID))) {
                nodeID = Number(nodeID);
            }

            if (nodeID === id) {
                return nodes[i];
            }
        }
        console.log(id + " is not in there!");
        return false;
        // It's not in there!
    }


    //countyNodes已经进行了过滤了 就是在当前选择州的countyNodes以及第一次导入的州的Id
    function importTotalCountyFlowData(flowPath, stateFIPS, countyNodes, callback) {
        d3.json(flowPath, function (flowDatas) {
            var flowData = flowDatas.links;
            var allNodes = flowDatas.nodes;
            var aFIPS,
                bFIPS,
                flow,
                flows = [],
                i, j,
                aPt,
                bPt,
                BtoA,
                AtoB,
                flowAB,
                flowBA,
                row,
                A_stateFIPS,
                B_stateFIPS,
                //startTime = performance.now(),
                endTime;

            // For each row in the table...
            for (i = 0, j = flowData.length; i < j; i += 1) {
                row = flowData[i];
                A_stateFIPS = row.o;
                B_stateFIPS = row.d;
                if (A_stateFIPS / 100 < 2 && B_stateFIPS / 100 < 2) {//出去State与State之间的flow
                    continue;
                }

                aPt = findNodeByID(countyNodes, A_stateFIPS);
                bPt = findNodeByID(countyNodes, B_stateFIPS);

                if (aPt && bPt) { // If both points exist in county nodes...
                    var AtoB = flowDatas.links.filter((link) => {
                        return link.o == aPt.id && link.d == bPt.id;
                    });
                    if (AtoB.length > 0) {
                        AtoB = AtoB[0].v[24];
                    }

                    var BtoA = flowDatas.links.filter((link) => {
                        return link.o == bPt.id && link.d == aPt.id;
                    });

                    if (BtoA.length > 0) {
                        BtoA = BtoA[0].v[24];
                    }

                    if (isNaN(BtoA) || isNaN(AtoB)) {
                        throw new Error("FlowImporter 二级的Flow边值必须为一个数值");
                    }

                    flowBA = new Flox.Flow(bPt, aPt, BtoA); // Make the BtoA flow
                    flowAB = new Flox.Flow(aPt, bPt, AtoB); // make the AtoB flow

                    // If the value of BA is bigger than 0...
                    if (BtoA > 0) {
                        flows.push(flowBA);
                        aPt.totalIncomingFlow += BtoA;
                        aPt.netFlow += BtoA;

                        bPt.totalOutgoingFlow += BtoA;
                        bPt.netFlow -= BtoA;
                    }

                    if (AtoB > 0) {
                        flows.push(flowAB);
                        aPt.totalOutgoingFlow += AtoB;
                        aPt.netFlow -= AtoB;

                        bPt.totalIncomingFlow += AtoB;
                        bPt.netFlow += AtoB;
                    }
                }
            }
            console.log(flows.length + " 条flows 在一级Id为 " + stateFIPS);
            //endTime = performance.now() - startTime;
            //console.log("import time: " + endTime);
            callback(flows, countyNodes);
        })
    }


// PUBLIC ---------------------------------------------------------------------


    /**
     * Imports a CSV file into the model
     *
     * @param {string} path File path to CSV.
     */
    my.importCSV = function (path) {

        // d3 has a convenient csv importer funtion
        d3.csv(path, function (data) {

            var i,
                j,
                sLat,
                sLng,
                eLat,
                eLng,
                value,
                startPt,
                endPt,
                sVal,
                eVal;

            for (i = 0,
                     j = data.length; i < j; i += 1) {
                // For every line, build a flow
                sLng = Number(data[i].lng0);
                sLat = Number(data[i].lat0);
                sVal = Number(data[i].val0);
                eLng = Number(data[i].lng1);
                eLat = Number(data[i].lat1);
                eVal = Number(data[i].val1);
                value = Number(data[i].value);

                startPt = new Flox.Point(sLat, sLng, sVal);
                endPt = new Flox.Point(eLat, eLng, eVal);

                Flox.addFlow(new Flox.Flow(startPt, endPt, value));
            }

            // Refresh the map. This will wait until the .csv is fully loaded.
            // This is because it is placed within the d3.csv() function.
            // If FloxController called refreshmap, it would run before
            // the CSV is fully loaded. D3 creates this delay here.
            Flox.sortFlows();

            Flox.setFilteredFlows();

            Flox.layoutFlows();

            Flox.refreshMap(); // FIXME this should happen in a callback.
        });
    };

    /**
     * Imports a CSV file containing formatted US Census county centroids to
     * be used as nodes for county-to-county flow data.
     * Only imports county nodes for the state designated by stateFIPS.
     * @param {Object} nodePath : Path to CSV
     * @param {Object} callback : Called after CSV is fully imported, with the
     * imported nodes as an argument.
     */
    my.importUSCensusCountyNodes = function (nodePath, stateFIPS, callback) {

        // import state nodes. Will be used to replace nodes outside of the
        // target state (stateFIPS).
        var newStNode,
            stateNodeData,
            row, i;

        // Import state nodes first. State nodes will replace county nodes that
        // are out side of the target state.
        importStateNodes(function (nodes) {
            // Import county nodes.
            d3.json(nodePath, function (flows) {
                var nodeData = flows.nodes
                var newPt;

                for (i = 0; i < nodeData.length; i += 1) {
                    row = nodeData[i];

                    // Is the node in-state?
                    // If so, add it.
                    if (Number(row.sId) === Number(stateFIPS)) {
                        // It's in-state, or there isn't a state node for it.
                        newPt = new Flox.Point(Number(row.y), Number(row.x), 1, row.id);

                        // new point migth not have an xy if the latLng is outside the
                        // d3 projection boundary, which causes errors. Don't add it to
                        // nodes if so. Flows with these point's won't be added to the
                        // model.
                        // FIXME Use a projection that enables showing everything?
                        //if (newPt.x && newPt.y) {
                        newPt.STATEFP = row.sId;
                        newPt.name = row.name;
                        newPt.totalIncomingFlow = 0;
                        newPt.totalOutgoingFlow = 0;
                        newPt.netFlow = 0;
                        newPt.type = "county";
                        nodes.push(newPt);
                        //}
                    }
                }
                callback(nodes);
            })
        });
    };

    /**
     * Imports the US Census county to county migration flows for one state.
     * @param {Object} stateFIPS : FIPS of selected state
     * @param {Object} callback : Passes along imported flows and nodes.
     */
    my.importTotalCountyFlowData = function (stateFIPS, callback) {

        var nodePath = "FlowData.json",
            flowPath = "FlowData.json";

        // Import nodes for all counties
        my.importUSCensusCountyNodes(nodePath, stateFIPS, function (countyNodes) {
            // countyNodes is the imported nodes!
            importTotalCountyFlowData(flowPath, stateFIPS, countyNodes, function (flows) {
                // flows are the imported flows!
                callback(flows, countyNodes);
            });
        });
    };

    /**
     * Imports the US Census state to state migration flows
     * 导入州到州的OD Flows串
     */
    my.importStateToStateMigrationFlows = function (flowPath, callback) {
        // Arrays to store the stuff
        var flows = [];

        // 导入州节点数据
        importStateNodes(function (nodes) {
            // 导入其他数据
            d3.json(flowPath, function (flowDatas) {
                var flowData = flowDatas.links
                var endID,
                    startID,
                    flow, val, endPt, startPt,
                    i;

                // For each row in the table...
                for (i = 0; i < flowData.length; i += 1) {
                    // 查找对应的节点 以获取坐标等相关属性信息
                    startPt = findNodeByID(nodes, flowData[i].o);
                    endPt = findNodeByID(nodes, flowData[i].d);
                    val = Number(flowData[i].v[24]);

                    if (startPt && endPt) {
                        if (val > 0) {
                            flows.push(new Flox.Flow(startPt, endPt, val));
                            startPt.totalOutgoingFlow += val;
                            startPt.netFlow -= val;
                            endPt.totalIncomingFlow += val;
                            endPt.netFlow += val;
                        }
                    }
                }
                callback(flows, nodes);
            })
        });
    };

    return my;
}(d3));
export default FlowImporter